import re

from rest_framework import serializers
from django.contrib.auth.models import User
from django_redis import get_redis_connection
from rest_framework_jwt.settings import api_settings


class RegiserSerializer(serializers.ModelSerializer):
    """
        用户注册序列化器
            需反序列化字段（校验） username、password、confirm_password、email、sig
            需要序列化字段（输出） username、email、token
    """
    confirm_password = serializers.CharField(label='确认密码', write_only=True)
    sig = serializers.CharField(label='签名', write_only=True, allow_blank=True)
    token = serializers.CharField(label='登录凭证', read_only=True)

    class Meta:
        model = User
        fields = ['username', 'password', 'confirm_password', 'email', 'sig', 'token']
        extra_kwargs = {
            # 修改 User 模型中的字段选项
            'username': {
                'min_length': 5,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许5-20个字符的⽤户名。',
                    'max_length': '仅允许5-20个字符的⽤户名。',
                }
            },
            'password': {
                'write_only': True,
                'min_length': 8,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许8-20个字符的密码。',
                    'max_length': '仅允许8-20个字符的密码。',
                }
            }
        }

    def validate_email(self, value):
        '''
            校验 email 格式
        '''
        if not value:
            raise serializers.ValidationError({'email': '该字段不能为空。'})
        if not re.match(r'^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$', value):
            raise serializers.ValidationError({'email': '邮箱格式错误。'})

        return value

    def validate(self, attrs):
        '''
            校验密码
            sig 签名签证
        '''
        # 校验密码是否一致
        if attrs['password'] != attrs['confirm_password']:
            raise serializers.ValidationError({'password': '两次密码不一致。'})

        # 校验 sig 签证
        redis_conn = get_redis_connection('verfication')
        if not redis_conn.get('email_%s_active' % attrs['email']):
            raise serializers.ValidationError({'email': '该邮箱未认证，请认证邮箱。'})
        if redis_conn.get('email_%s_sig' % attrs['email']).decode() != attrs['sig']:
            raise serializers.ValidationError({'email': '验证失败。'})
        return attrs

    def create(self, validated_data):
        '''
            重写 create 方法，去除非存储数据，并入库
        '''
        del validated_data['confirm_password']
        del validated_data['sig']
        raw_password = validated_data.pop('password')
        user = User(**validated_data)
        user.set_password(raw_password)  # 将明文password加密，并赋值给password字段
        user.save()

        # 清空 redis 缓存，防止 二次 创建账号
        redis_conn = get_redis_connection('verfication')
        pl = redis_conn.pipeline()
        pl.delete('email_%s' % validated_data['email'])
        pl.delete('email_%s_flag' % validated_data['email'])
        pl.delete('email_%s_sig' % validated_data['email'])
        pl.delete('email_%s_active' % validated_data['email'])
        pl.execute()

        # 生成 token
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        user.token = token
        return user

